import java.io.Serializable;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Queue;
import java.util.Vector;
import java.util.Collection;

public class Table implements Serializable {

	public int tableNumber;
	public int MaximumPlayers;
	public boolean isWinnerSet;
	public String winnerNick;
	RoundManager RManager;
	CardManager CManager;
	PlayerManager PManager;
	ChatManager ChManager;
	public Vector<Card> cardsAtTable;
	public Vector<Player> tableWinners;
	public int ChipsValue;
	boolean GameInProgress;


	public Table(int TableNumber)
	{
		tableNumber = TableNumber;
		MaximumPlayers = 8;
		isWinnerSet = false;
		RManager = new RoundManager(tableNumber);
		CManager = new CardManager(tableNumber);
		PManager = new PlayerManager(tableNumber,0);
		ChManager = new ChatManager();
	    cardsAtTable = new Vector<Card>();
	    tableWinners = new Vector<Player>();
		CManager.shuffle();
		ChipsValue = 0;
		GameInProgress = false;
	}

	public void PlayerChecked(Player player, int currHigh){
		player.setState("Checked");
		player.updateBetAndCurrentWorth(currHigh);
	}

	public void PlayerRaised(Player player, int bet){
		player.setState("Raised");
		int value = player.getBet() + bet;
		ChipsValue+=bet;
		player.updateBetAndCurrentWorth(value);
		RManager.updateCurrentHigh(bet);
	}
	public void PlayerCalled(Player player){
		player.setState("Called");
		int currHigh = RManager.getCurrHigh();
		ChipsValue+=currHigh;
		player.updateBetAndCurrentWorth(currHigh);
		//RManager.updateCurrentHigh(currHigh);
	}

	public void PlayerFolded(Player player){
		player.setState("Folded");
	}

    public boolean checkTableState(){
		Player playerObject = null;
		boolean res;
		int counter = 0;
		Iterator itr = (PManager.getListOfPlayers()).iterator();
		//Find the player with this name
		while(itr.hasNext()){
			playerObject = (Player)itr.next();
			if(((playerObject.getState()).equals("Folded")) || ((playerObject.getState()).equals("Checked")) || (playerObject.getState()).equals("Queued"))
				counter++;
				//res = false;
		}
		if(counter == PManager.getCountofPlayers())
		{
			res = true;
		}
		else
			res = false;
		return (res);
	}

	public void TakeTableDecision(){

		if(RManager.getRoundID() == 2){
			Card[] FlopCards = new Card[3];
			FlopCards = CManager.getFlopCards();
			cardsAtTable.addElement(FlopCards[0]);
			cardsAtTable.addElement(FlopCards[1]);
			cardsAtTable.addElement(FlopCards[2]);
		}
		else if(RManager.getRoundID() == 3){
			Card TurnCard= new Card();
			TurnCard = CManager.getTurnCard();
			cardsAtTable.addElement(TurnCard);
		}
		else if(RManager.getRoundID() == 4){
			Card RiverCard= new Card();
			RiverCard = CManager.getRiverCard();
			cardsAtTable.addElement(RiverCard);
		}
		else if(RManager.getRoundID() == 5)
		{
			determineWinner();
			Iterator i = tableWinners.iterator();
			while(i.hasNext())
			{
				Player player = (Player) i.next();
				System.out.println(player.getName() + "  " + player.getFinalCardCombinationValue());
			}	
 		}
	}

	@SuppressWarnings("unchecked")
	public void determineWinner(){
		Vector comb = new Vector<Card>();
		Vector result = new Vector< Vector<Card> >();

		comb = (Vector<Card>)cardsAtTable.clone();
		Iterator iter = PManager.getListOfPlayers().iterator();
		while(iter.hasNext())
		{
			Player player = (Player) iter.next();
			int defaultVal = player.getFinalCardCombinationValue();

			Card[] cardlist = player.getCards();
			comb.add(cardlist[0]);
			comb.add(cardlist[1]);
			  for (int i = 0; i < 7; i++)
			  {
				  for (int j = 0; j < 7; j++)
				  {
					  if (i == j)
						  continue;
					  Vector temp = new Vector<Card>();
					  for (int k = 0; k < 7; k++) {
						  if (k != i && k != j) {
							  temp.addElement(comb.elementAt(k));
						  }
					  }
					  //System.out.println(temp);
					  //result.add(temp);

					//You have the combination for this player in temp
					//Determine the hand value
					Hand handValue = new Hand();
					for(int n = 0;n < 5; n++)
						handValue.setCard(n, (Card)temp.elementAt(n));

					//Get the value for this player
					int val = getHandValue(handValue);
					if(val < defaultVal)
						defaultVal = val;

				  }

			  }
			comb.remove(6);
			comb.remove(5);

			//Set the combination value for this player here
			player.setFinalCardCombinationValue(defaultVal);

		}

		//After values of all players have been determined, find out the winner player

		//Find out maximum value
		iter = PManager.getListOfPlayers().iterator();
		int valOfPlayer, max_val=10;
		while(iter.hasNext()){
			 Player player = (Player) iter.next();
			 if(!player.getState().equals("Folded") && !player.getState().equals("Queued")){
				 valOfPlayer = player.getFinalCardCombinationValue();
				 if( valOfPlayer <= max_val)
					 max_val= valOfPlayer;
			 }
		}

		//Find out winner players
		iter = PManager.getListOfPlayers().iterator();
		while(iter.hasNext()){
			 Player player = (Player) iter.next();
			 if(!player.getState().equals("Folded") && !player.getState().equals("Queued")){
				 valOfPlayer = player.getFinalCardCombinationValue();
				 if( valOfPlayer == max_val)
				 {
					 tableWinners.add(player);
				 }
			 }
		}
		iter = tableWinners.iterator();
		while(iter.hasNext())
		{
			Player player = (Player) iter.next();
			player.updateCurrentWorth(ChipsValue/tableWinners.size());
		}
		isWinnerSet = true;
	}
	
	public void RestartGame()
	{
		System.out.println("Restarting Game");
		isWinnerSet = false;
		winnerNick = "";
		cardsAtTable.removeAllElements();
		tableWinners.removeAllElements();
		ChipsValue = 0;
		
		RManager.resetRoundID();
		RManager.updateCurrentHigh(10 - this.RManager.getCurrHigh());
		
		CManager.shuffle();
		
		Iterator iter = PManager.getListOfPlayers().iterator();
		Player curr = null;
		while(iter.hasNext())
		{
			Player player = (Player) iter.next();
			player.setState("active");
			player.finalCardCombinationValue = 9;
			Card[] CardArray = new Card[2];
			CardArray = CManager.getHoleCards();
			player.setCards(CardArray);
			player.isCurrPlayer = false;
			player.setBet(0);
			if(player.isDealer)
			{
				curr = (Player) iter.next();
				/*
				curr.isCurrPlayer = true;
				curr.setBet(10);
				*/
			}			
		}
		curr.isCurrPlayer = true;
		curr.setBet(10);

		GameInProgress = true;
	}
	public void ClearTable()
	{
		
	}


	public int getHandValue(Hand hand){
	    if(hand.isRoyalFlush() == true)
	        return 0;
	    if(hand.isStraightFlush() == true)
	        return 1;
	    if(hand.isFourOfAKind() == true)
	        return 2;
	    if(hand.isFullHouse() == true)
	        return 3;
	    if(hand.isFlush() == true)
	        return 4;
	    if(hand.isStraight() == true)
	        return 5;
	    if(hand.isThreeOfAKind() == true)
	        return 6;
	    if(hand.isTwoPair() == true)
	        return 7;
	    if(hand.isPair() == true)
	        return 8;
	    return 9;
	}

	public synchronized boolean TakeRoundAction(Player PlayerObj){
		Player dealer = this.PManager.getDealer();
		boolean res=false;
		/* res= true if all players have currently checked or are queued
		   , res= false if some/all players have folded or raised */
			res = this.checkTableState();
				if(res){
					this.RManager.updateRoundID(); //if res=true, update roundID
					this.TakeTableDecision();
				}
				else{
					//Special case check: n-1 players have folded, the remaining player is the winner 
			        //Check if n-1 players have folded
					Player playerNotFolded = null;
					playerNotFolded = checkTableIfAllButOneFolded();
					if(playerNotFolded != null){
						/* There is a winner which is this player */
						tableWinners.add(playerNotFolded);						
						playerNotFolded.updateCurrentWorth(ChipsValue/tableWinners.size());
						isWinnerSet = true;
						}
					}
		return res;
		
	}
	
	public Player checkTableIfAllButOneFolded(){
		int count = 0;
		Player playerObject = null;
		Player winner = null;
		Iterator iter = PManager.getListOfPlayers().iterator();
		while(iter.hasNext()){
			playerObject = (Player)iter.next();
		    if(playerObject.getState().equals("Folded") || playerObject.getState().equals("Queued"))
		    	count++;
		    else
		    	winner = playerObject;
		}
		if(count == PManager.getCountofPlayers()-1) //there is a winner
			return winner;
		else
			return null;
		
	}

	public int getMaximumPlayers()
	{
		return MaximumPlayers;
	}
}
